/**
* personium.io
* Copyright 2014 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fujitsu.dc.core.bar;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.exc.UnrecognizedPropertyException;
import org.w3c.dom.Element;
import com.fujitsu.dc.common.es.util.IndexNameEncoder;
import com.fujitsu.dc.core.DcCoreException;
import com.fujitsu.dc.core.auth.AccessContext;
import com.fujitsu.dc.core.model.ctl.ExtRole;
import com.fujitsu.dc.core.model.ctl.Relation;
import com.fujitsu.dc.core.model.ctl.Role;
/**
* Httpリクエストボディからbarファイルを読み込むためのクラス.
*/
public class BarFileUtils {
private static final int PATH_CELL_INDEX = 1;
private static final int PATH_BOX_INDEX = 3;
private BarFileUtils() {
}
/**
* ACLの名前空間をバリデートする.
* この際、ついでにロールインスタンスURLへの変換、BaseURLの変換を行う。
* @param entryName エントリ名
* @param element Elementノード
* @param schemaUrl BoxスキーマURL
* @return 処理結果
*/
public static boolean aclNameSpaceValidate(final String entryName, final Element element, final String schemaUrl) {
return true;
}
/**
* 70_$links.jsonのFromName/ToNameに関する複合キーを取得する.
* @param type FromType/ToNameに指定されたEntitySet名
* @param names FromName/ToNameに指定されたEntityKey名
* @param boxName Box名
* @return Entity作成時に使用するEntityKey名
*/
public static String getComplexKeyName(final String type, final Map<String, String> names, final String boxName) {
String keyname = null;
// 複合キー
if (type.equals(Role.EDM_TYPE_NAME) || type.equals(Relation.EDM_TYPE_NAME)) {
keyname = String.format("(Name='%s',_Box.Name='%s')", names.get("Name"), boxName);
// URI(ExtRole)
} else if (type.equals(ExtRole.EDM_TYPE_NAME)) {
keyname = String.format("(ExtRole='%s',_Relation.Name='%s',_Relation._Box.Name='%s')",
names.get("ExtRole"), names.get("_Relation.Name"), boxName);
// その他
} else {
keyname = String.format("(Name='%s')", names.get("Name"));
}
return keyname;
}
/**
* barファイル内に記載されたURLのホスト情報(scheme://hostname/)を処理中サーバの情報へ置換する.
* @param url 変更対象のURL(エンコードされていないURL)
* @param baseUrl インポート先のURL
* @param fileName 処理中のbarファイルエントリ名
* @return 生成したURL
*/
public static String getLocalUrl(final String url, final String baseUrl, final String fileName) {
String newUrl = baseUrl;
if (newUrl.endsWith("/")) {
newUrl = newUrl.substring(0, newUrl.length() - 1);
}
try {
newUrl = newUrl + new URL(url).getPath();
} catch (MalformedURLException e) {
throw DcCoreException.BarInstall.JSON_FILE_FORMAT_ERROR.params(fileName);
}
return newUrl;
}
/**
* ACLの名前空間をバリデートする.
* この際、ついでにロールインスタンスURLへの変換、BaseURLの変換を行う。
* @param element element
* @param baseUrl baseUrl
* @param cellName cellName
* @param boxName boxName
* @return 生成したElementノード
*/
public static Element convertToRoleInstanceUrl(
final Element element, final String baseUrl, final String cellName, final String boxName) {
String namespaceUri = element.getAttribute("xml:base");
String roleClassUrl = getLocalUrl(namespaceUri, baseUrl, BarFileReadRunner.ROOTPROPS_XML);
Element retElement = (Element) element.cloneNode(true);
String[] paths = null;
try {
URL url = new URL(roleClassUrl);
paths = url.getPath().split("/");
} catch (MalformedURLException e) {
throw DcCoreException.BarInstall.JSON_FILE_FORMAT_ERROR.params(BarFileReadRunner.ROOTPROPS_XML);
}
// ロールクラスURLからロールインスタンスURLへ変換して属性として設定
StringBuilder newBaseUrl = null;
String url = baseUrl;
if (url.endsWith("/")) {
url = url.substring(0, url.lastIndexOf("/"));
}
newBaseUrl = new StringBuilder(url);
paths[PATH_CELL_INDEX] = cellName;
paths[PATH_BOX_INDEX] = boxName;
for (String path : paths) {
if (path.length() == 0) {
continue;
}
newBaseUrl.append("/");
newBaseUrl.append(path);
}
newBaseUrl.append("/");
retElement.setAttribute("xml:base", newBaseUrl.toString());
return retElement;
}
/**
* Cellオーナー情報からUnitUser名を取得する.
* @param owner オーナー情報(URL)
* @return UnitUser名
*/
public static String getUnitUserName(final String owner) {
String unitUserName = null;
if (owner == null) {
unitUserName = AccessContext.TYPE_ANONYMOUS;
} else {
unitUserName = IndexNameEncoder.encodeEsIndexName(owner);
}
return unitUserName;
}
/**
* barファイルエントリからJSONファイルを読み込む.
* @param <T> JSONMappedObject
* @param inStream barファイルエントリのInputStream
* @param entryName entryName
* @param clazz clazz
* @return JSONファイルから読み込んだオブジェクト
* @throws IOException JSONファイル読み込みエラー
*/
public static <T> T readJsonEntry(
InputStream inStream, String entryName, Class<T> clazz) throws IOException {
JsonParser jp = null;
ObjectMapper mapper = new ObjectMapper();
JsonFactory f = new JsonFactory();
jp = f.createJsonParser(inStream);
JsonToken token = jp.nextToken(); // JSONルート要素("{")
Pattern formatPattern = Pattern.compile(".*/+(.*)");
Matcher formatMatcher = formatPattern.matcher(entryName);
String jsonName = formatMatcher.replaceAll("$1");
T json = null;
if (token == JsonToken.START_OBJECT) {
try {
json = mapper.readValue(jp, clazz);
} catch (UnrecognizedPropertyException ex) {
throw DcCoreException.BarInstall.JSON_FILE_FORMAT_ERROR.params(jsonName);
}
} else {
throw DcCoreException.BarInstall.JSON_FILE_FORMAT_ERROR.params(jsonName);
}
return json;
}
}